﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace EasyTrader.Wave
{
    using PricePointList = List<PricePoint>;
    using PriceWaveList = List<PriceWave>;

    public class WaveManager
    {
        /// <summary>
        /// 데이터 셋에 대한 정보를 가지고 있다.
        /// 여기에 현재 모든 원시 데이터들이 들어 있다.
        /// </summary>
        private ETDataSet m_EasyTraderDataSet;
        private PricePointList m_PriceList = new PricePointList();
        public PricePointList PriceList
        {
            get { return m_PriceList; }
            set { m_PriceList = value; }
        }
        private PricePointList m_FirstPriceList = new PricePointList();
        public PricePointList FirstPriceList
        {
            get { return m_FirstPriceList; }
            set { m_FirstPriceList = value; }
        }
        private PriceWaveList m_FirstWaveList = new PriceWaveList();
        public PriceWaveList FirstWaveList
        {
            get { return m_FirstWaveList; }
            set { m_FirstWaveList = value; }
        }

        private PriceWaveList m_MiddleWaveList = new PriceWaveList();

        private PricePointList m_MiddlePointList = new PricePointList();

        private PricePointList m_FilteredPointList = new PricePointList();
        public PricePointList FilteredPointList
        {
            get { return m_FilteredPointList; }
            set { m_FilteredPointList = value; }
        }
        private PriceWaveList m_FilteredWaveList = new PriceWaveList();
        private PriceWaveList m_MergedWaveList = new PriceWaveList();
        private PriceWaveList m_ArragedWaveList = new PriceWaveList();
        public PriceWaveList ArragedWaveList
        {
            get { return m_ArragedWaveList; }
            set { m_ArragedWaveList = value; }
        }


        public WaveManager(ETDataSet a_DataSet)
        {
            m_EasyTraderDataSet = a_DataSet;
        }

        public WaveManager()
        {
            m_EasyTraderDataSet = null;
        }

        public EasyTrader.ETDataSet EasyTraderDataSet
        {
            get { return m_EasyTraderDataSet; }
            set { m_EasyTraderDataSet = value; }
        }

        public void MakeWaveListFromFutOptChart()
        {
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return;
            MakeWave(curTable);
        }

        public void MakeWaveListForBuy()
        {
            FutureMstTable curTable = m_EasyTraderDataSet.GetFutureMstTable();
            if (curTable == null)
                return;
            MakeWaveForBuy(curTable);
        }

        public void MakeWaveListForSell()
        {
            FutureMstTable curTable = m_EasyTraderDataSet.GetFutureMstTable();
            if (curTable == null)
                return;
            MakeWaveForSell(curTable);
        }


        private int FindHighLowIndex(int a_StartIndex, double a_HeightLimit, ref int a_HighIndex, ref int a_LowIndex, ref double a_Min, ref double a_Max, ref double a_Amp)
        {


            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null || a_StartIndex < 0)
                return -1;

            DataRow row = curTable.Rows[a_StartIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);

            //double max = open;
            //double min = open;
            a_Min = open;
            a_Max = open;
            for (int i = a_StartIndex; i < curTable.GetRowCount(); i++)
            {
                row = curTable.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);
                if (high > a_Max)
                {
                    a_Max = high;
                    a_HighIndex = i;
                }
                if (low < a_Min)
                {
                    a_Min = low;
                    a_LowIndex = i;
                }

                if (a_HighIndex != a_LowIndex && (a_Max - a_Min) > a_HeightLimit)
                    break;
            }

            return Math.Max(a_HighIndex, a_LowIndex);
        }

        private PricePointList m_WavePointList = new PricePointList();

        private void MakeWavePoint()
        {
            double Ratio = 2.0;
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return;
            if (curTable.GetRowCount() < 3)
                return;

            m_WavePointList.Clear();

            DataRow row = curTable.Rows[0];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);

            double heightLimit = 0.9;
            double deltaHigh = 0;
            double deltaLow = 0;
            double min = open;
            double max = open;
            double amp = 0.0;

            int highIndex = 0;
            int lowIndex = 0;
            int mode = GlobalVar.PriceFlat;

            EasyTrader.Wave.PricePoint newPoint = new EasyTrader.Wave.PricePoint();
            newPoint.X = 0;
            newPoint.Y = open;
            m_WavePointList.Add(newPoint);

            // 먼저 최초 진폭에 맞는 점을 찾아 온다. 
            FindHighLowIndex(0, 1.0, ref highIndex, ref lowIndex, ref min, ref max, ref amp);

            int startIndex = Math.Max(highIndex, lowIndex);
            if (highIndex < lowIndex)
            {
                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = highIndex;
                newPoint.Y = max;
                m_WavePointList.Add(newPoint);
                newPoint.Mode = GlobalVar.PriceUp;
            }
            else
            {
                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = lowIndex;
                newPoint.Y = min;
                m_WavePointList.Add(newPoint);
                newPoint.Mode = GlobalVar.PriceDown;
            }

            EasyTrader.Wave.PricePoint lastPoint = null;
            for (int i = startIndex; i < curTable.GetRowCount(); i++)
            {
                lastPoint = m_WavePointList[m_WavePointList.Count - 1];
                EasyTrader.Wave.PricePoint prevPoint = m_WavePointList[m_WavePointList.Count - 2];
                row = curTable.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);

                if (high > max)
                {
                    max = high;
                    highIndex = i;
                }
                if (low < min)
                {
                    min = low;
                    lowIndex = i;
                }

                amp = max - min;

                if (curTable.GetRowCount() > 2)
                {
                    DataRow preRow = curTable.Rows[i - 1];
                    double preHigh = Convert.ToDouble(preRow["고가"]);
                    double preLow = Convert.ToDouble(preRow["저가"]);

                    // 고점 모드일때
                    if (highIndex > lowIndex)
                    {
                        // 고점이 하락이면 점을 추가한다.
                        deltaHigh = high - preHigh;
                        if (deltaHigh <= 0)
                        {
                            if (lastPoint.Mode != GlobalVar.PriceUp && amp > heightLimit && Math.Abs(highIndex - lowIndex) >= 1)
                            {
                                newPoint = new EasyTrader.Wave.PricePoint();
                                newPoint.X = i - 1;
                                newPoint.Y = preHigh;
                                newPoint.Mode = GlobalVar.PriceUp;
                                m_WavePointList.Add(newPoint);

                                heightLimit = amp / Ratio;
                                min = preLow;
                                max = preHigh;
                                highIndex = i - 1;
                                lowIndex = i - 1;
                            }

                        }
                        else if (deltaHigh > 0)
                        {
                            if (lastPoint.Mode == GlobalVar.PriceUp && high > lastPoint.Y)
                            {
                                //lastPoint.Y = high;
                                //lastPoint.X = i + 1;
                                if (prevPoint != null && prevPoint.Mode == GlobalVar.PriceDown)
                                {
                                    lastPoint.Y = high;
                                    lastPoint.X = i;
                                    heightLimit = (high - prevPoint.Y) / Ratio;
                                    //min = high;
                                    max = high;
                                    highIndex = i;
                                    //lowIndex = i;
                                }
                            }
                        }
                    }
                    else if (lowIndex > highIndex) // 저점 모드 일때 
                    {
                        // 저점이 상승이면 점을 추가한다.
                        deltaLow = low - preLow;
                        if (deltaLow >= 0)
                        {
                            if (lastPoint.Mode != GlobalVar.PriceDown && amp > heightLimit && Math.Abs(highIndex - lowIndex) >= 1)
                            {
                                newPoint = new EasyTrader.Wave.PricePoint();
                                newPoint.X = i - 1;
                                newPoint.Y = preLow;
                                newPoint.Mode = GlobalVar.PriceDown;
                                m_WavePointList.Add(newPoint);

                                heightLimit = amp / Ratio;
                                min = preLow;
                                max = preHigh;
                                highIndex = i - 1;
                                lowIndex = i - 1;
                            }

                        }
                        else if (deltaLow < 0)
                        {
                            if (lastPoint.Mode == GlobalVar.PriceDown && low < lastPoint.Y)
                            {
                                //lastPoint.Y = low;
                                //lastPoint.X = i + 1;
                                if (prevPoint != null && prevPoint.Mode == GlobalVar.PriceUp)
                                {
                                    lastPoint.Y = low;
                                    lastPoint.X = i;
                                    heightLimit = (low - prevPoint.Y) / Ratio;
                                    min = low;
                                    //max = low;
                                    //highIndex = i;
                                    lowIndex = i;
                                }
                            }
                        }
                    }
                }
            }


            lastPoint = m_WavePointList[m_WavePointList.Count - 1];
            row = curTable.Rows[curTable.GetRowCount() - 1];
            high = Convert.ToDouble(row["고가"]);
            low = Convert.ToDouble(row["저가"]);

            FindHighLowIndex(lastPoint.X, 2.0, ref highIndex, ref lowIndex, ref min, ref max, ref amp);
            
            if (lastPoint.Mode == GlobalVar.PriceDown)
            {
                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = highIndex;
                newPoint.Y = max;
                newPoint.Mode = GlobalVar.PriceUp;
                m_WavePointList.Add(newPoint);



                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = curTable.GetRowCount() - 1;
                newPoint.Y = high;
                newPoint.Mode = GlobalVar.PriceUp;
                m_WavePointList.Add(newPoint);
            }
            else
            {
                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = lowIndex;
                newPoint.Y = min;
                newPoint.Mode = GlobalVar.PriceDown;
                m_WavePointList.Add(newPoint);

                newPoint = new EasyTrader.Wave.PricePoint();
                newPoint.X = curTable.GetRowCount() - 1;
                newPoint.Y = low;
                newPoint.Mode = GlobalVar.PriceDown;
                m_WavePointList.Add(newPoint);
            }
        }


        public int GetWaveCrossDownCount(double a_CurVal, double a_IndexVal, double a_Range, PriceWaveList a_WaveList)
        {
            int crossCount = 0;
            int maxCount = 0;
            for (int i = 0; i < a_WaveList.Count; i++)
            {
                PriceWave wave = a_WaveList[i];
                crossCount = 0;
                for (double j = a_IndexVal; j >= a_IndexVal - a_Range; j = j - 0.05)
                {
                    if (wave.Slope == GlobalVar.PriceUp)
                    {
                        if (j >= wave.StartY && j <= wave.EndY)
                            crossCount++;
                    }
                    else if (wave.Slope == GlobalVar.PriceDown)
                    {
                        if (j <= wave.StartY && j >= wave.EndY)
                            crossCount++;
                    }
                }
                if (crossCount > maxCount)
                    maxCount = crossCount;
            }

            return maxCount;
        }

        public int GetWaveCrossDownCount(int a_CurIndex, double a_IndexVal, double a_Range, double a_CurVal, int a_MaxLen)
        {
            int maxCount = 0;
            int len = 0;
            if (a_CurVal <= a_IndexVal && a_CurVal >= a_IndexVal - 0.1)
            {
                for (double j = a_IndexVal; j >= a_IndexVal - a_Range; j = j - 0.05)
                {
                    int crossCount = 0;
                    len = 0;
                    for (int i = m_FirstWaveList.Count - 1; i >= 0; i--)
                    {
                        PriceWave wave = m_FirstWaveList[i];
                        double max = Math.Max(wave.StartY, wave.EndY);
                        double min = Math.Min(wave.StartY, wave.EndY);
                        if (j >= min && j <= max)
                            crossCount++;

                        len += wave.Length();
                        if (len >= a_MaxLen)
                            break;
                    }
                    if (crossCount > maxCount)
                        maxCount = crossCount;
                }
            }

            return maxCount;
        }

        public int GetWaveCrossUpCount(int a_CurIndex, double a_IndexVal, double a_Range, double a_CurVal, int a_MaxLen)
        {
            int maxCount = 0;
            int len = 0;
            if (a_CurVal <= a_IndexVal && a_CurVal >= a_IndexVal - 0.1)
            {
                for (double j = a_IndexVal; j <= a_IndexVal + a_Range; j = j + 0.05)
                {
                    int crossCount = 0;
                    len = 0;
                    for (int i = m_FirstWaveList.Count - 1; i >= 0; i--)
                    {
                        PriceWave wave = m_FirstWaveList[i];
                        double max = Math.Max(wave.StartY, wave.EndY);
                        double min = Math.Min(wave.StartY, wave.EndY);
                        if (j >= min && j <= max)
                            crossCount++;

                        len += wave.Length();
                        if (len >= a_MaxLen)
                            break;
                    }
                    if (crossCount > maxCount)
                        maxCount = crossCount;
                }
            }

            return maxCount;
        }

        public int GetWaveCrossUpCount(double a_IndexVal, double a_Range)
        {
            int crossCount = 0;
            int maxCount = 0;
            for (int i = 0; i < m_FirstWaveList.Count; i++)
            {
                PriceWave wave = m_FirstWaveList[i];
                crossCount = 0;
                for (double j = a_IndexVal; j <= a_IndexVal + a_Range; j = j + 0.05)
                {
                    if (wave.Slope == GlobalVar.PriceUp)
                    {
                        if (j >= wave.StartY && j <= wave.EndY)
                            crossCount++;
                    }
                    else if (wave.Slope == GlobalVar.PriceDown)
                    {
                        if (j <= wave.StartY && j >= wave.EndY)
                            crossCount++;
                    }
                }
                if (crossCount > maxCount)
                    maxCount = crossCount;
            }

            return maxCount;
        }

        public EasyTrader.Wave.PriceWave GetCurWave(int a_CurIndex)
        {
            int count = m_ArragedWaveList.Count;
            if (count == 0)
                return null;

            for (int i = 0; i < count; i++)
            {
                EasyTrader.Wave.PriceWave wave = m_ArragedWaveList[i];
                if (wave.StartX <= a_CurIndex && a_CurIndex <= wave.EndX)
                    return wave;
            }

            return null;
        }

        public EasyTrader.Wave.PriceWave GetCurFirstWave(int a_CurIndex)
        {
            int count = m_FirstWaveList.Count;
            if (count == 0)
                return null;

            for (int i = count - 1; i >= 0; i--)
            {
                EasyTrader.Wave.PriceWave wave = m_FirstWaveList[i];
                if (wave.StartX <= a_CurIndex && a_CurIndex <= wave.EndX)
                    return wave;
            }

            return null;
        }

        public EasyTrader.Wave.PriceWave GetPreWave(int a_CurIndex)
        {
            int count = m_ArragedWaveList.Count;
            if (count == 0)
                return null;

            int index = 0;
            for (int i = 0; i < count; i++)
            {
                EasyTrader.Wave.PriceWave wave = m_ArragedWaveList[i];
                if (wave.StartX <= a_CurIndex && a_CurIndex <= wave.EndX)
                {
                    index = i;
                    break;
                }
            }

            if (index - 1 < 0)
                return null;
            else
                return m_ArragedWaveList[index - 1];
        }

        // 실시간으로 파동을 가져올 때 쓴다.
        public EasyTrader.Wave.PriceWave GetCurWave()
        {
            int count = m_ArragedWaveList.Count;
            if (count == 0)
                return null;

            EasyTrader.Wave.PriceWave wave = m_ArragedWaveList[count - 1];

            return wave;
        }

        // 이전 파동을 가져온다.
        public EasyTrader.Wave.PriceWave GetPreWave()
        {
            int count = m_ArragedWaveList.Count;
            if (count < 2)
                return null;

            EasyTrader.Wave.PriceWave wave = m_ArragedWaveList[count - 1];

            return wave;
        }

        public static bool IsSameWave(PriceWave a_FirstWave, PriceWave a_SecondWave)
        {
            if (a_FirstWave == null || a_SecondWave == null)
                return false;
            if (a_FirstWave.StartX == a_SecondWave.StartX &&
                a_FirstWave.EndX == a_SecondWave.EndX &&
                a_FirstWave.StartY == a_SecondWave.StartY &&
                a_FirstWave.EndY == a_SecondWave.EndY)
                return true;
            else
                return false;
        }
        // 파동의 근원이 같은지 검사한다.
        public static bool IsSameWaveSource(PriceWave a_FirstWave, PriceWave a_SecondWave)
        {
            if (a_FirstWave == null || a_SecondWave == null)
                return false;
            if (a_FirstWave.StartX == a_SecondWave.StartX &&
                a_FirstWave.StartY == a_SecondWave.StartY )
                return true;
            else
                return false;
        }
        public void MakeWaveListFromFutOptChart(int a_DataCount)
        {
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return;
            int dataCount = Math.Min(a_DataCount, curTable.GetRowCount());
            MakeWave(dataCount, curTable);
        }

        public void MakeWaveListForCall(int a_DataCount)
        {
            CPSvrNew7221Table curTable = m_EasyTraderDataSet.GetCPSvrNew7221Table();
            if (curTable == null)
                return;
            int dataCount = Math.Min(a_DataCount, curTable.GetRowCount());
            MakeWaveForCall(dataCount, curTable);
        }

        public void MakeWaveListForPut(int a_DataCount)
        {
            CPSvrNew7221Table curTable = m_EasyTraderDataSet.GetCPSvrNew7221Table();
            if (curTable == null)
                return;
            int dataCount = Math.Min(a_DataCount, curTable.GetRowCount());
            MakeWaveForPut(dataCount, curTable);
        }

        public void MakeWaveListForBuy(int a_DataCount)
        {
            FutureMstTable curTable = m_EasyTraderDataSet.GetFutureMstTable();
            if (curTable == null)
                return;
            int dataCount = Math.Min(a_DataCount, curTable.GetRowCount());
            MakeWaveForBuy(dataCount, curTable);
        }

        public void MakeWaveListForSell(int a_DataCount)
        {
            FutureMstTable curTable = m_EasyTraderDataSet.GetFutureMstTable();
            if (curTable == null)
                return;
            int dataCount = Math.Min(a_DataCount, curTable.GetRowCount());
            MakeWaveForSell(dataCount, curTable);
        }

        public void MakeWaveListFromCmeMst()
        {
            CmeMstTable curTable = m_EasyTraderDataSet.GetCmeMstTable();
            if (curTable == null)
                return;
            MakeWave(curTable);
        }

        // 이 함수는 주어진 파동에서 기준에 맞는 파동만을 찾아 냅니다.
        public void ExtractWave(PriceWaveList a_SourceWaveList, PriceWaveList a_TargetWaveList)
        {
            if (a_SourceWaveList.Count == 0)
                return;
            a_TargetWaveList.Clear();
            // 처음 파동은 단절을 피하기 위하여 그대로 추가해 준다.
            a_TargetWaveList.Add(a_SourceWaveList[0]);
            // 파동에서 모든 점들을 가져 온다.
            int sourceCount = a_SourceWaveList.Count;
            for (int i = 1; i < sourceCount; i++)
            {
                PriceWave curWave = a_SourceWaveList[i];
                if (curWave.Length() >= 1)
                {
                    if (curWave.Height() >= 0.15)
                    {
                        a_TargetWaveList.Add(curWave);
                    }
                    else
                    {
                        if (curWave.Length() >= 5)
                        {
                            if (curWave.Height() >= 0.1)
                            {
                                a_TargetWaveList.Add(curWave);
                            }
                            else
                            {
                                if (i == sourceCount - 1)
                                    a_TargetWaveList.Add(curWave);
                            }
                        }
                        else
                        {
                            if (i == sourceCount - 1)
                                a_TargetWaveList.Add(curWave);
                        }
                    }
                }
                else
                {
                    if (i == sourceCount - 1)
                        a_TargetWaveList.Add(curWave);
                }
            }
        } // Extract Wave End.

        public double SumWaveHeight(PriceWaveList a_WaveList, int a_UpDown)
        {
            double sum = 0.0;
            for (int i = 0; i < a_WaveList.Count; i++)
            {
                PriceWave wave = a_WaveList[i];
                if (wave.Slope == a_UpDown)
                {
                    sum = wave.Height();
                }
            }
            return sum;
        }


        public double SumWaveHeight(int a_UpDown)
        {
            double sum = 0.0;
            for (int i = 0; i < m_FirstWaveList.Count; i++)
            {
                PriceWave wave = m_FirstWaveList[i];
                if (wave.Slope == a_UpDown)
                {
                    sum += wave.Height();
                }
            }
            return sum;
        }

        public void FindTurningPoint(int a_CurIndex, PriceWaveList a_WaveList, PricePointList a_OutList, DataTable a_DataTable, string a_ColName)
        {
            // 파동에서 모든 점들을 가져 온다.
            int sourceCount = a_WaveList.Count;
            if (sourceCount == 0)
                return;
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;

            if (a_CurIndex < 0)
                a_CurIndex = 0;
            if (a_CurIndex > rowCount - 1)
                a_CurIndex = rowCount - 1;

            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            int X = 0;
            double Y = Convert.ToDouble(row[a_ColName]);

            PricePoint newPoint = new PricePoint();
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.UpDown = GlobalVar.PriceFlat;
            a_OutList.Add(newPoint);
            
            // Get the first data row on the table.
            
            for (int i = 0; i <= a_CurIndex; i++)
            {
                row = curTable.Rows[i];
                X = i;
                Y = Convert.ToDouble(row[a_ColName]);

                // 현재 값이 속해 있는 파동을 찾는다.
                int waveIndex = -1;
                for (int k = sourceCount - 1; k >= 0; k--)
                {
                    PriceWave wave = a_WaveList[k];
                    if (i > wave.StartX && i <= wave.EndX)
                    {
                        waveIndex = k;
                        break;
                    }
                }

                // 찾은 파동에서 이전 신호가 나올 때까지 역추적해 들어간다.
                PricePoint lastPoint = a_OutList[a_OutList.Count - 1];
                for (int j = waveIndex; j >= 0; j--)
                {
                    PriceWave wave = a_WaveList[j];
                    if (wave.Slope == GlobalVar.PriceDown)
                    {
                        double deltaY = wave.StartY - Y;
                        if (deltaY >= 0.35)
                        {
                            if (wave.StartX == 335)
                            {
                                int p = 0;
                                p = p + 1;
                            }
                            AddPriceItem(a_OutList, wave.StartX, wave.StartY, GlobalVar.PriceDown);
                        }
                    }
                    else if (wave.Slope == GlobalVar.PriceUp)
                    {
                        double deltaY = Y - wave.StartY;
                        if (deltaY >= 0.35)
                        {
                            if (wave.StartX == 335)
                            {
                                int p = 0;
                                p = p + 1;
                            }
                            AddPriceItem(a_OutList, wave.StartX, wave.StartY, GlobalVar.PriceUp);
                        }
                    }

                    if (wave.StartX == lastPoint.X)
                        break;
                }
            }

            // 맨 마지막 점 추가
            row = curTable.Rows[a_CurIndex];
            X = a_CurIndex;
            Y = Convert.ToDouble(row[a_ColName]);
            newPoint = new PricePoint();
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.UpDown = GlobalVar.PriceFlat;
            a_OutList.Add(newPoint);
        }

        public void FindTurningPoint(int a_CurIndex, PriceWaveList a_WaveList, PricePointList a_OutList, DataTable a_DataTable, string a_ColName, double a_MinTurnVal)
        {
            // 파동에서 모든 점들을 가져 온다.
            int sourceCount = a_WaveList.Count;
            if (sourceCount == 0)
                return;
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;

            if (a_CurIndex < 0)
                a_CurIndex = 0;
            if (a_CurIndex > rowCount - 1)
                a_CurIndex = rowCount - 1;

            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            int X = 0;
            double Y = Convert.ToDouble(row[a_ColName]);

            PricePoint newPoint = new PricePoint();
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.UpDown = GlobalVar.PriceFlat;
            a_OutList.Add(newPoint);

            // Get the first data row on the table.

            for (int i = 0; i <= a_CurIndex; i++)
            {
                row = curTable.Rows[i];
                X = i;
                Y = Convert.ToDouble(row[a_ColName]);

                // 현재 값이 속해 있는 파동을 찾는다.
                int waveIndex = -1;
                for (int k = sourceCount - 1; k >= 0; k--)
                {
                    PriceWave wave = a_WaveList[k];
                    if (i > wave.StartX && i <= wave.EndX)
                    {
                        waveIndex = k;
                        break;
                    }
                }

                // 찾은 파동에서 이전 신호가 나올 때까지 역추적해 들어간다.
                PricePoint lastPoint = a_OutList[a_OutList.Count - 1];
                for (int j = waveIndex; j >= 0; j--)
                {
                    PriceWave wave = a_WaveList[j];
                    if (wave.Slope == GlobalVar.PriceDown)
                    {
                        double deltaY = wave.StartY - Y;
                        if (deltaY >= a_MinTurnVal)
                        {
                            if (wave.StartX == 335)
                            {
                                int p = 0;
                                p = p + 1;
                            }
                            AddPriceItem(a_OutList, wave.StartX, wave.StartY, GlobalVar.PriceDown);
                        }
                    }
                    else if (wave.Slope == GlobalVar.PriceUp)
                    {
                        double deltaY = Y - wave.StartY;
                        if (deltaY >= a_MinTurnVal)
                        {
                            if (wave.StartX == 335)
                            {
                                int p = 0;
                                p = p + 1;
                            }
                            AddPriceItem(a_OutList, wave.StartX, wave.StartY, GlobalVar.PriceUp);
                        }
                    }

                    if (wave.StartX == lastPoint.X)
                        break;
                }
            }

            // 맨 마지막 점 추가
            row = curTable.Rows[a_CurIndex];
            X = a_CurIndex;
            Y = Convert.ToDouble(row[a_ColName]);
            newPoint = new PricePoint();
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.UpDown = GlobalVar.PriceFlat;
            a_OutList.Add(newPoint);
        }


        public void AddPriceItem(PricePointList a_List, int a_X, double a_Y, int a_UpDown)
        {
            int count = a_List.Count;
            PricePoint newPoint = null;
            /*
            if (count == 0)
            {
                newPoint = new PricePoint();
                newPoint.X = a_X;
                newPoint.Y = a_Y;
                a_List.Add(newPoint);
                return;
            }*/

            PricePoint lastPoint = a_List[count - 1];
            if (a_X > lastPoint.X && lastPoint.UpDown != a_UpDown)
            {
                if (a_X == 26)
                {
                    int p = 0;
                    p = p + 1;
                }
                newPoint = new PricePoint();
                newPoint.X = a_X;
                newPoint.Y = a_Y;
                newPoint.UpDown = a_UpDown;
                a_List.Add(newPoint);
            }
        }


        // 이 함수는 파동에서 순수 포인트 목록을 찾아 냅니다.
        public bool ExtractPoint(PriceWaveList a_WaveList, PricePointList a_PointList)
        {
            // 먼저 목록을 초기화 해준다.
            a_PointList.Clear();
            // 파동에서 모든 점들을 가져 온다.
            int sourceCount = a_WaveList.Count;
            if (sourceCount == 0)
                return false;
            // 단절을 피하기 위하여 첫 점은 무조건 추가해 준다.
            PriceWave oldWave = a_WaveList[0];
            PricePoint newPoint = new PricePoint();
            newPoint.X = oldWave.StartX;
            newPoint.Y = oldWave.StartY;
            a_PointList.Add(newPoint);
            for (int i = 0; i < sourceCount; i++)
            {
                PriceWave curWave = a_WaveList[i];
                if (oldWave != null && oldWave.EndX != curWave.StartX)
                {
                    int deltaX = curWave.StartX - oldWave.EndX;
                    double deltaHeight = Math.Abs(curWave.StartY - oldWave.EndY);
                    if (deltaX >= 1 && deltaHeight >= 0.15)
                    {
                        newPoint = new PricePoint();
                        newPoint.X = oldWave.EndX;
                        newPoint.Y = oldWave.EndY;
                        a_PointList.Add(newPoint);
                    }
                }
                if (i == sourceCount - 1)
                {
                    if (curWave.Length() < 1)
                    {
                        newPoint = new PricePoint();
                        newPoint.X = curWave.EndX;
                        newPoint.Y = curWave.EndY;
                        a_PointList.Add(newPoint);
                        //a_PointList.Add(curWave.EndPoint);
                    }
                    else
                    {
                        newPoint = new PricePoint();
                        newPoint.X = curWave.StartX;
                        newPoint.Y = curWave.StartY;
                        a_PointList.Add(newPoint);

                        newPoint = new PricePoint();
                        newPoint.X = curWave.EndX;
                        newPoint.Y = curWave.EndY;
                        a_PointList.Add(newPoint);
                        //a_PointList.Add(curWave.StartPoint);
                        //a_PointList.Add(curWave.EndPoint);
                    }
                }
                else
                {
                    newPoint = new PricePoint();
                    newPoint.X = curWave.StartX;
                    newPoint.Y = curWave.StartY;
                    a_PointList.Add(newPoint);
                    //a_PointList.Add(curWave.StartPoint);
                }
                oldWave = curWave;
            }
            return true;
        }

        public void MakeWave(DataTable a_DataTable)
        {
            /*
            ExractPointList(m_FirstPriceList, a_DataTable, "시가", "종가");
            FindWave(m_FirstPriceList, m_FirstWaveList);
            ExtractPointListByDA(m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "시가", "종가");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            MergeWave(m_FilteredWaveList, m_MergedWaveList);
            RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            //FindMiddleLine(m_FirstWaveList, m_MiddlePointList);
            //FindWave(m_MiddlePointList, m_MiddleWaveList);
            //ExtractWave(m_MiddleWaveList, m_FilteredWaveList);
            //ExtractPoint(m_FilteredWaveList, m_FilteredPointList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            //FindWave(m_FilteredPointList, m_ArragedWaveList);
             */
            MakeWavePoint();
            FindWave(m_WavePointList, m_ArragedWaveList);
        }

        public void MakeWave(int a_DataCount, DataTable a_DataTable)
        {
            /*
            ExractPointList(a_DataCount, m_FirstPriceList, a_DataTable, "시가", "종가");
            FindWave(m_FirstPriceList, m_FirstWaveList);
            ExtractPointListByDA(a_DataCount, m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "시가", "종가");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            MergeWave(m_FilteredWaveList, m_MergedWaveList);
            RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            //FindMiddleLine(m_FirstWaveList, m_MiddlePointList);
            //FindWave(m_MiddlePointList, m_ArragedWaveList);
            //ExtractWave(m_MiddleWaveList, m_FilteredWaveList);
            //ExtractPoint(m_FilteredWaveList, m_FilteredPointList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            //FindWave(m_FilteredPointList, m_ArragedWaveList);
             */
            ExractPointList(a_DataCount, m_FirstPriceList, a_DataTable, "시가", "종가");
            FindWave(m_FirstPriceList, m_FirstWaveList);
            FindTurningPoint(a_DataCount - 1, m_FirstWaveList, m_FilteredPointList, a_DataTable, "종가");
            FindWave(m_FilteredPointList, m_ArragedWaveList);
        }

        public void MakeWaveForBuy(int a_DataCount, DataTable a_DataTable)
        {
            ExractPointList(a_DataCount, m_FirstPriceList, a_DataTable, "매수총호가건수", "매수총호가건수");
            FindWave(m_FirstPriceList, m_FilteredWaveList);
            //MergeWaveForBuySell(m_FilteredWaveList, m_MergedWaveList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            FindTurningPoint(a_DataCount - 1, m_FilteredWaveList, m_FilteredPointList, a_DataTable, "매수총호가건수", 250.0);
            FindWave(m_FilteredPointList, m_ArragedWaveList);
        }

        public void MakeWaveForCall(int a_DataCount, DataTable a_DataTable)
        {
            ExtractPointListByDA(a_DataCount, m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "개인옵션콜순매수", "개인옵션콜순매수");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            //MergeWaveForCallPut(m_FilteredWaveList, m_MergedWaveList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            FindTurningPoint(a_DataCount - 1, m_FilteredWaveList, m_FilteredPointList, a_DataTable, "개인옵션콜순매수", 1000.0);
            FindWave(m_FilteredPointList, m_ArragedWaveList);
        }

        public void MakeWaveForPut(int a_DataCount, DataTable a_DataTable)
        {
            ExtractPointListByDA(a_DataCount, m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "개인옵션풋순매수", "개인옵션풋순매수");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            //MergeWaveForCallPut(m_FilteredWaveList, m_MergedWaveList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            FindTurningPoint(a_DataCount - 1, m_FilteredWaveList, m_FilteredPointList, a_DataTable, "개인옵션풋순매수", 1000.0);
            FindWave(m_FilteredPointList, m_ArragedWaveList);
        }

        public void MakeWaveForBuy(DataTable a_DataTable)
        {
            ExtractPointListByDA(m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "매수총호가건수", "매수총호가건수");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            MergeWaveForBuySell(m_FilteredWaveList, m_MergedWaveList);
            RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
        }

        public void MakeWaveForSell(int a_DataCount, DataTable a_DataTable)
        {
            ExractPointList(a_DataCount, m_FirstPriceList, a_DataTable, "매도총호가건수", "매도총호가건수");
            FindWave(m_FirstPriceList, m_FilteredWaveList);
            //MergeWaveForBuySell(m_FilteredWaveList, m_MergedWaveList);
            //RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
            FindTurningPoint(a_DataCount - 1, m_FilteredWaveList, m_FilteredPointList, a_DataTable, "매도총호가건수", 250.0);
            FindWave(m_FilteredPointList, m_ArragedWaveList);
        }

        public void MakeWaveForSell(DataTable a_DataTable)
        {
            ExtractPointListByDA(m_FilteredPointList, GlobalVar.FirstAveFilterVal, GlobalVar.SecondAveFilterVal, a_DataTable, "매도총호가건수", "매도총호가건수");
            FindWave(m_FilteredPointList, m_FilteredWaveList);
            MergeWaveForBuySell(m_FilteredWaveList, m_MergedWaveList);
            RearrangeWave(m_MergedWaveList, m_ArragedWaveList);
        }

        public void ExtractClosePriceFutOptChart()
        {
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return;
            ExractPointList(m_PriceList, curTable, "시가", "종가");
        }

        public void ExtractPriceFutOptChart(string a_ColumnName)
        {
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return;
            ExractPointList(m_PriceList, curTable, "시가", a_ColumnName);
        }

        private void ExractPointList(PricePointList a_OutList, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            //newPoint.X = X;
            //newPoint.Y = Y;
            //newPoint.Time = Convert.ToDouble(row["시각"]);
            //a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < rowCount; i++)
            {
                row = curTable.Rows[i];
                X = i;
                Y = Convert.ToDouble(row[a_YCol2Name]);
                if (Y == 0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = Y;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }
        }

        private void ExractPointList(int a_DataCount, PricePointList a_OutList, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            if (a_DataCount < 1)
                return;
            if (a_DataCount > rowCount)
                a_DataCount = rowCount;
            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            //newPoint.X = X;
            //newPoint.Y = Y;
            //newPoint.Time = Convert.ToDouble(row["시각"]);
            //a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < a_DataCount; i++)
            {
                row = curTable.Rows[i];
                X = i;
                Y = Convert.ToDouble(row[a_YCol2Name]);
                if (Y == 0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = Y;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }
        }


        private void FindWaveMinus(PricePointList a_PricePointList, PriceWaveList a_WaveList)
        {
            // 값 목록이 2보다 작을 때는 아무일도 하지 않는다.
            if (a_PricePointList.Count < 2)
                return;
            // 먼저 출력 목록을 비워준다.
            a_WaveList.Clear();

            PricePoint firstPoint = a_PricePointList[0];
            PricePoint lastPoint = firstPoint;
            PriceWave newWave = new PriceWave();
            newWave.StartX = firstPoint.X;
            newWave.StartY = firstPoint.Y;
            int oldSlope = GlobalVar.PriceFlat;
            int curSlope = GlobalVar.PriceFlat;

            for (int i = 1; i < a_PricePointList.Count; i++)
            {
                firstPoint = a_PricePointList[i - 1];
                lastPoint = a_PricePointList[i];
                double incValue = lastPoint.Y - firstPoint.Y;
                if (incValue > 0)
                {
                    curSlope = GlobalVar.PriceUp;
                }
                else if (incValue < 0)
                {
                    curSlope = GlobalVar.PriceDown;
                }
                else
                {
                    curSlope = oldSlope;
                }

                if (oldSlope != GlobalVar.PriceFlat && oldSlope != curSlope)
                {
                    newWave.EndX = firstPoint.X - 1;
                    newWave.EndY = firstPoint.Y;
                    newWave.Slope = oldSlope;
                    a_WaveList.Add(newWave);
                    newWave = new PriceWave();
                    newWave.StartX = firstPoint.X - 1;
                    newWave.StartY = firstPoint.Y;
                }

                oldSlope = curSlope;
            }
            newWave.EndX = lastPoint.X - 1;
            newWave.EndY = lastPoint.Y;
            newWave.Slope = oldSlope;
            a_WaveList.Add(newWave);
        }

        private void FindWave(PricePointList a_PricePointList, PriceWaveList a_WaveList)
        {
            // 값 목록이 2보다 작을 때는 아무일도 하지 않는다.
            if (a_PricePointList.Count < 2)
                return;
            // 먼저 출력 목록을 비워준다.
            a_WaveList.Clear();

            PricePoint firstPoint = a_PricePointList[0];
            PricePoint lastPoint = firstPoint;
            PriceWave newWave = new PriceWave();
            newWave.StartX = firstPoint.X;
            newWave.StartY = firstPoint.Y;
            int oldSlope = GlobalVar.PriceFlat;
            int curSlope = GlobalVar.PriceFlat;

            for (int i = 1; i < a_PricePointList.Count; i++)
            {
                firstPoint = a_PricePointList[i - 1];
                lastPoint = a_PricePointList[i];
                double incValue = lastPoint.Y - firstPoint.Y;
                if (incValue > 0)
                {
                    curSlope = GlobalVar.PriceUp;
                }
                else if (incValue < 0)
                {
                    curSlope = GlobalVar.PriceDown;
                }
                else
                {
                    curSlope = oldSlope;
                }

                if (oldSlope != GlobalVar.PriceFlat && oldSlope != curSlope)
                {
                    newWave.EndX = firstPoint.X;
                    newWave.EndY = firstPoint.Y;
                    newWave.Slope = oldSlope;
                    a_WaveList.Add(newWave);
                    newWave = new PriceWave();
                    newWave.StartX = firstPoint.X;
                    newWave.StartY = firstPoint.Y;
                }

                oldSlope = curSlope;
            }
            newWave.EndX = lastPoint.X;
            newWave.EndY = lastPoint.Y;
            newWave.Slope = oldSlope;
            a_WaveList.Add(newWave);
        }

        // 이 함수는 가장 최근의 파동에서 시작하여 기준 높이 이상이 되는 마지막 파동을 찾는다.
        // 기준 높이는 1.1 포인트이다. 이것은 고가와 저가를 기준으로 찾는다.
        // 파동은 어디까지 조사할 것인지를 지시한다. 현재 파동의 10분이전까지 조사해 보고 없으면
        // 다음 파동의 10분전까지 조사하는 방식으로 진행을 한다.
        // 반환되는 파동속에 이 구간의 고점과 저점이 들어간다.
        public PriceWave FindSignalWave(PriceWaveList a_WaveList, int a_CurIndex)
        {
            if (a_WaveList == null || m_EasyTraderDataSet == null)
                return null;
            int count = a_WaveList.Count;
            if (count == 0)
                return null;
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return null;
            int rowCount = curTable.GetRowCount();
            if (rowCount == 0)
                return null;
            if (a_CurIndex < 0 || a_CurIndex > rowCount - 1)
                return null;
            DataRow row = curTable.Rows[a_CurIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            PriceWave signalWave = new PriceWave();
            signalWave.StartX = a_CurIndex;
            signalWave.EndX = a_CurIndex;
            signalWave.StartY = low;
            signalWave.EndY = high;
            int startX = rowCount - 1;
            for (int i = count - 1; i >= 0; i--)
            {
                PriceWave wave = a_WaveList[i];
                int endX = wave.StartX;
                endX = Math.Max(startX - 10, 0);
                for (int j = startX; j >= endX; j--)
                {
                    row = curTable.Rows[j];
                    high = Convert.ToDouble(row["고가"]);
                    low = Convert.ToDouble(row["저가"]);
                    if (low < signalWave.StartY)
                        signalWave.StartY = low;
                    if (high > signalWave.EndY)
                        signalWave.EndY = high;
                }
                double deltaY = signalWave.Height();
                if (deltaY >= GlobalVar.SignalWaveHeight)
                    break;
                startX = endX;
            }

            return signalWave;
        }

        public int FindMiddleLine(PriceWaveList a_SourceWaveList, PricePointList a_TargetPointList)
        {
            if (a_SourceWaveList.Count < 1)
                return -1;
            // 먼저 출력 목록을 비워준다.
            a_TargetPointList.Clear();
            PriceWave curWave = a_SourceWaveList[0];
            PricePoint newPoint = new PricePoint();
            if (a_SourceWaveList.Count == 1)
            {
                newPoint.X = curWave.StartX;
                newPoint.Y = curWave.StartY;
                a_TargetPointList.Add(newPoint);
                newPoint = new PricePoint();
                newPoint.X = curWave.EndX;
                newPoint.Y = curWave.EndY;
                a_TargetPointList.Add(newPoint);
                return 1;
            }
            else
            {
                newPoint.X = curWave.StartX;
                newPoint.Y = curWave.StartY;
                a_TargetPointList.Add(newPoint);
            }
            for (int i = 0; i < a_SourceWaveList.Count; i++)
            {
                curWave = a_SourceWaveList[i];
                newPoint = new PricePoint();
                // 인덱스의 중간 값을 취한다.
                int valueX = (int)((curWave.StartX + curWave.EndX) / 2);
                // 종가의 중간 값을 취한다.
                double valueY = (curWave.StartY + curWave.EndY) / 2;
                // 파동의 중간 값을 저장
                newPoint.Y = valueY;
                // 파동의 중간 인덱스 저장
                newPoint.X = valueX;
                // 목록에 넣어 준다.
                a_TargetPointList.Add(newPoint);
            }
            return 1;
        } // FindMiddleLine End.

        public PriceWave FindSignalWave(PriceWaveList a_WaveList, int a_CurIndex, ref PriceWave signalWave)
        {
            if (a_WaveList == null || m_EasyTraderDataSet == null)
                return null;
            int count = a_WaveList.Count;
            if (count == 0)
                return null;
            EasyTrader.DataSet.FutOptChartTable curTable = m_EasyTraderDataSet.GetFutOptChartTable();
            if (curTable == null)
                return null;
            int rowCount = curTable.GetRowCount();
            if (rowCount == 0)
                return null;
            if (a_CurIndex < 0 || a_CurIndex > rowCount - 1)
                return null;
            DataRow row = curTable.Rows[a_CurIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            //PriceWave signalWave = new PriceWave();
            signalWave.StartX = a_CurIndex;
            signalWave.EndX = a_CurIndex;
            signalWave.StartY = low;
            signalWave.EndY = high;
            int startX = rowCount - 1;
            for (int i = count - 1; i >= 0; i--)
            {
                PriceWave wave = a_WaveList[i];
                int endX = wave.StartX;
                endX = Math.Max(startX - 10, 0);
                for (int j = startX; j >= endX; j--)
                {
                    row = curTable.Rows[j];
                    high = Convert.ToDouble(row["고가"]);
                    low = Convert.ToDouble(row["저가"]);
                    if (low < signalWave.StartY)
                        signalWave.StartY = low;
                    if (high > signalWave.EndY)
                        signalWave.EndY = high;
                }
                double deltaY = signalWave.Height();
                if (deltaY >= GlobalVar.SignalWaveHeight)
                    break;
                startX = endX;
            }

            return signalWave;
        }

        private void ExtractPointListByDA(PricePointList a_OutList, int a_FirstAverage, int a_SecondAverage, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.Time = Convert.ToDouble(row["시각"]);
            a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < rowCount - 1; i++)
            {
                row = curTable.Rows[i];
                X = i + 1;
                Y = Convert.ToDouble(row[a_YCol2Name]);
                if (Y == 0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = Y;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }

            if (a_OutList.Count > a_FirstAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_FirstAverage, a_OutList, j);
                    if (j + a_FirstAverage - 1 >= 0)
                    {
                        if (j + a_FirstAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_FirstAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }

            if (a_OutList.Count > a_SecondAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_SecondAverage, a_OutList, j);
                    if (j + a_SecondAverage - 1 >= 0)
                    {
                        if (j + a_SecondAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_SecondAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }
        }

        private void ExtractPointListByDA(PricePointList a_OutList, int a_FirstAverage, int a_SecondAverage, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name, string a_YCol3Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.Time = Convert.ToDouble(row["시각"]);
            a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < rowCount - 1; i++)
            {
                row = curTable.Rows[i];
                X = i + 1;
                double val1 = Convert.ToDouble(row[a_YCol2Name]);
                double val2 = Convert.ToDouble(row[a_YCol3Name]);
                if (val1 == 0.0 || val2 == 0.0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = (val1 + val2) / 2.0;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }

            if (a_OutList.Count > a_FirstAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_FirstAverage, a_OutList, j);
                    if (j + a_FirstAverage - 1 >= 0)
                    {
                        if (j + a_FirstAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_FirstAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }

            if (a_OutList.Count > a_SecondAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_SecondAverage, a_OutList, j);
                    if (j + a_SecondAverage - 1 >= 0)
                    {
                        if (j + a_SecondAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_SecondAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }
        }

        private void ExtractPointListByDA(int a_DataCount, PricePointList a_OutList, int a_FirstAverage, int a_SecondAverage, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            if (a_DataCount < 1)
                return;
            if (a_DataCount > rowCount)
                a_DataCount = rowCount;

            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.Time = Convert.ToDouble(row["시각"]);
            a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < a_DataCount; i++)
            {
                row = curTable.Rows[i];
                X = i + 1;
                Y = Convert.ToDouble(row[a_YCol2Name]);
                if (Y == 0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = Y;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }

            if (a_OutList.Count > a_FirstAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_FirstAverage, a_OutList, j);
                    if (j + a_FirstAverage - 1 >= 0)
                    {
                        if (j + a_FirstAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_FirstAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }

            if (a_OutList.Count > a_SecondAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_SecondAverage, a_OutList, j);
                    if (j + a_SecondAverage - 1 >= 0)
                    {
                        if (j + a_SecondAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_SecondAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }
        }

        private void ExtractPointListByDA(int a_DataCount, PricePointList a_OutList, int a_FirstAverage, int a_SecondAverage, DataTable a_DataTable, string a_YCol1Name, string a_YCol2Name, string a_YCol3Name)
        {
            if (m_EasyTraderDataSet == null)
                return;
            DataTable curTable = a_DataTable;

            if (curTable == null)
                return;
            int rowCount = curTable.Rows.Count;
            if (rowCount == 0)
                return;
            if (a_DataCount < 1)
                return;
            if (a_DataCount > rowCount)
                a_DataCount = rowCount;

            // 먼저 목록을 비워준다.
            a_OutList.Clear();

            DataRow row = curTable.Rows[0];
            PricePoint newPoint = new PricePoint();
            int X = 0;
            double Y = Convert.ToDouble(row[a_YCol1Name]);
            newPoint.X = X;
            newPoint.Y = Y;
            newPoint.Time = Convert.ToDouble(row["시각"]);
            a_OutList.Add(newPoint);
            // Get the first data row on the table.
            for (int i = 0; i < a_DataCount; i++)
            {
                row = curTable.Rows[i];
                X = i + 1;
                double val1 = Convert.ToDouble(row[a_YCol2Name]);
                double val2 = Convert.ToDouble(row[a_YCol3Name]);
                if (val1 == 0.0 || val2 == 0.0)
                    continue;
                newPoint = new PricePoint();
                newPoint.X = X;
                newPoint.Y = (val1 + val2) / 2.0;
                newPoint.Time = Convert.ToDouble(row["시각"]);
                a_OutList.Add(newPoint);
            }

            if (a_OutList.Count > a_FirstAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_FirstAverage, a_OutList, j);
                    if (j + a_FirstAverage - 1 >= 0)
                    {
                        if (j + a_FirstAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_FirstAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }

            if (a_OutList.Count > a_SecondAverage - 1)
            {
                for (int j = 0; j < a_OutList.Count; j++)
                {
                    PricePoint point = a_OutList[j];
                    double ave = SimpleMACD(a_SecondAverage, a_OutList, j);
                    if (j + a_SecondAverage - 1 >= 0)
                    {
                        if (j + a_SecondAverage - 1 >= a_OutList.Count)
                            break;
                        PricePoint avePoint = a_OutList[j + a_SecondAverage - 1];
                        avePoint.Y = ave;
                    }
                }
            }
        }

        private void MergeWave(PriceWaveList a_SourceWaveList, PriceWaveList a_TargetWaveList)
        {
            if (a_SourceWaveList.Count < 1 || GlobalVar.WaveLenLimit < 0)
                return;
            // 먼저 출력 목록을 비워준다.
            a_TargetWaveList.Clear();

            if (a_SourceWaveList.Count == 1)
            {
                PriceWave firstWave = a_SourceWaveList[a_SourceWaveList.Count - 1];
                a_TargetWaveList.Add(firstWave.Clone());
                return;
            }

            int WaveState = GlobalVar.WaveFit;
            PriceWave newWave = null;
            for (int i = 0; i < a_SourceWaveList.Count; i++)
            {
                PriceWave curWave = a_SourceWaveList[i];
                // 이전 파동이 기준에 부합하는 경우
                if (WaveState == GlobalVar.WaveFit)
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= GlobalVar.WaveHeightLimit)
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
                else // 이전 파동이 기준에 부합하지 않는 경우
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= GlobalVar.WaveHeightLimit)
                    {
                        // 현재 파동의 끝점을 넣어 준다.
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        // 목록에 넣어 준다.
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
            }
        }


        private void MergeWaveForBuySell(PriceWaveList a_SourceWaveList, PriceWaveList a_TargetWaveList)
        {
            if (a_SourceWaveList.Count < 1 || GlobalVar.WaveLenLimit < 0)
                return;
            // 먼저 출력 목록을 비워준다.
            a_TargetWaveList.Clear();

            if (a_SourceWaveList.Count == 1)
            {
                PriceWave firstWave = a_SourceWaveList[a_SourceWaveList.Count - 1];
                a_TargetWaveList.Add(firstWave.Clone());
                return;
            }

            int WaveState = GlobalVar.WaveFit;
            PriceWave newWave = null;
            for (int i = 0; i < a_SourceWaveList.Count; i++)
            {
                PriceWave curWave = a_SourceWaveList[i];
                // 이전 파동이 기준에 부합하는 경우
                if (WaveState == GlobalVar.WaveFit)
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= 100)
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
                else // 이전 파동이 기준에 부합하지 않는 경우
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= 100)
                    {
                        // 현재 파동의 끝점을 넣어 준다.
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        // 목록에 넣어 준다.
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
            }
        }

        private void MergeWaveForCallPut(PriceWaveList a_SourceWaveList, PriceWaveList a_TargetWaveList)
        {
            if (a_SourceWaveList.Count < 1 || GlobalVar.WaveLenLimit < 0)
                return;
            // 먼저 출력 목록을 비워준다.
            a_TargetWaveList.Clear();

            if (a_SourceWaveList.Count == 1)
            {
                PriceWave firstWave = a_SourceWaveList[a_SourceWaveList.Count - 1];
                a_TargetWaveList.Add(firstWave.Clone());
                return;
            }

            int WaveState = GlobalVar.WaveFit;
            PriceWave newWave = null;
            for (int i = 0; i < a_SourceWaveList.Count; i++)
            {
                PriceWave curWave = a_SourceWaveList[i];
                // 이전 파동이 기준에 부합하는 경우
                if (WaveState == GlobalVar.WaveFit)
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= 200)
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave = curWave.Clone();
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
                else // 이전 파동이 기준에 부합하지 않는 경우
                {
                    // 현재 파동이 기준에 부합하지 않는 경우
                    if (curWave.Length() <= GlobalVar.WaveLenLimit || curWave.Height() <= 200)
                    {
                        // 현재 파동의 끝점을 넣어 준다.
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        WaveState = GlobalVar.WaveUnFit;
                    }
                    else // 현재 파동이 기준에 부합하는 경우
                    {
                        newWave.EndX = curWave.EndX;
                        newWave.EndY = curWave.EndY;
                        // 파동의 트렌드를 새로 계산해서 넣어 준다.
                        double inc = newWave.EndY - newWave.StartY;
                        if (inc < 0)
                            newWave.Slope = GlobalVar.PriceDown;
                        else if (inc > 0)
                            newWave.Slope = GlobalVar.PriceUp;
                        else
                            newWave.Slope = GlobalVar.PriceFlat;
                        // 목록에 넣어 준다.
                        a_TargetWaveList.Add(newWave);
                        WaveState = GlobalVar.WaveFit;
                    }
                }
            }
        }

        private void RearrangeWave(PriceWaveList a_SourceWaveList, PriceWaveList a_TargetWaveList)
        {
            int waveCount = a_SourceWaveList.Count;
            if (waveCount < 1)
                return;
            // 먼저 출력 목록을 비워준다.
            a_TargetWaveList.Clear();

            if (waveCount == 1)
            {
                a_TargetWaveList.Add(a_SourceWaveList[0]);
                return;
            }

            PriceWave firstWave = null;
            PriceWave curWave = null;
            PriceWave newWave = null;
            PriceWave oldWave = a_SourceWaveList[0];
            bool sameWave = false;
            bool sameWaveStarted = false;
            for (int i = 1; i < waveCount; i++)
            {
                curWave = a_SourceWaveList[i];
                if (curWave.Slope == oldWave.Slope)
                {
                    sameWave = true;
                    if (sameWaveStarted == false)
                    {
                        firstWave = oldWave;
                        sameWaveStarted = true;
                    }
                }
                else
                {
                    if (sameWave == true)
                    {
                        newWave = MergeWave(firstWave, oldWave);
                        a_TargetWaveList.Add(newWave);
                    }
                    else
                    {
                        a_TargetWaveList.Add(oldWave);
                    }
                    sameWave = false;
                    sameWaveStarted = false;
                }
                // 마지막 파동일 때
                if (i == waveCount - 1)
                {
                    if (sameWaveStarted == true)
                    {
                        newWave = MergeWave(firstWave, curWave);
                        a_TargetWaveList.Add(newWave);
                    }
                    else
                    {
                        a_TargetWaveList.Add(curWave);
                    }
                }
                oldWave = curWave;
            }
        }

        public PriceWave MergeWave(PriceWave a_FirstWave, PriceWave a_SecondWave)
        {
            if (a_FirstWave.StartX < a_SecondWave.StartX)
            {
                a_FirstWave.EndX = a_SecondWave.EndX;
                a_FirstWave.EndY = a_SecondWave.EndY;
                // 파동의 트렌드를 새로 계산해서 넣어 준다.
                double inc = a_FirstWave.EndY - a_FirstWave.StartY;
                if (inc < 0)
                    a_FirstWave.Slope = GlobalVar.PriceDown;
                else if (inc > 0)
                    a_FirstWave.Slope = GlobalVar.PriceUp;
                else
                    a_FirstWave.Slope = GlobalVar.PriceFlat;
                return a_FirstWave;
            }
            else
            {
                a_SecondWave.EndX = a_FirstWave.EndX;
                a_SecondWave.EndY = a_FirstWave.EndY;
                // 파동의 트렌드를 새로 계산해서 넣어 준다.
                double inc = a_SecondWave.EndY - a_SecondWave.StartY;
                if (inc < 0)
                    a_SecondWave.Slope = GlobalVar.PriceDown;
                else if (inc > 0)
                    a_SecondWave.Slope = GlobalVar.PriceUp;
                else
                    a_SecondWave.Slope = GlobalVar.PriceFlat;
                return a_SecondWave;
            }
        } // MergeWave End.

        public double SimpleMACD(int a_NumberOfDays, PricePointList prices, int a_StartIndex)
        {
            if (a_StartIndex < 0 || a_NumberOfDays == 0)
                return -1.0;

            double average = 0.0;
            for (int i = a_StartIndex; i < a_StartIndex + a_NumberOfDays; i++)
            {
                if (i >= prices.Count)
                    break;
                average += prices[i].Y;
            }
            average = average / a_NumberOfDays;

            return average;
        }
    }
}
